package com.example.demo;

import com.example.demo.Dao.PersonRepository;
import com.example.demo.Entity.Person;
import com.example.demo.Security.CustomUserDeatailImpl;
import com.example.demo.Security.JavaWebTokenConfigurer;
import com.example.demo.Utils.RedisUtils;
import lombok.Cleanup;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 开启Swagger
 * 可以了 我退出回话你启动试试
 *
 * */
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@SpringBootApplication
@EnableScheduling
public class IntelligenceCommunitySystemApplication {

    @Value("${server.ssl.key-store}")
    private String path;

    private static ConcurrentHashMap<String,String> testPerson = new ConcurrentHashMap<>();

    public static Integer inviteCode;


    @RestController
    public static class CodeController{
//        @Resource
//        public RedisUtils redisUtils;
//        @Resource
//        public PersonRepository personRepository;
        @GetMapping("/authentication/worker/code")
        public Integer getInviteCode()
        {
            return IntelligenceCommunitySystemApplication.inviteCode;
        }
//        @PutMapping("/authentication/testperson/register")
//        public String register(@RequestParam String username,@RequestParam String password)
//        {
//            try {
////                当缓存中有用户的缓存信息时，表示用户已在系统中，不允许其他人注册
//                if (redisUtils.hasKey(username)){
//                    return "注册失败，用户名已存在";
//                }
////                查询数据库
//                Person person  = personRepository.findByUsername(username);
//                if (person!=null){
//                    return "注册失败，用户名已存在";
//                }
//                personRepository.save(Person.builder().username(username).password(password).build());
//                return "注册成功";
//            }catch (Exception e){
//                return "注册失败";
//            }
//        }
//        @GetMapping("/authentication/testperson/login")
//        public String login(@RequestParam String username,@RequestParam String password)
//        {
//            try {
//                if (redisUtils.hasKey(username)){
//                    return password.equals(redisUtils.get(username).toString())?"登录成功":"登录失败";
//                }
//                Person person =  personRepository.findByUsername(username);
//                return person==null?"登录失败，没有找到该用户":person.getPassword().equals(password)?"登录成功":"登录失败，密码错误";
//            }catch (Exception e){
//                return "登录失败";
//            }
//        }
    }

    public static void main(String[] args) {
        SpringApplication.run(IntelligenceCommunitySystemApplication.class, args);

    }
    @Scheduled(cron =" ${wjl.Schedule.updateTime}")
    public void reportCurrentTime() throws IOException {
        System.out.println("动态码进行了更换");

        inviteCode = new Random(System.currentTimeMillis()).nextInt(90000)+10000;
        System.out.println(inviteCode);
    };
    @Bean
    public CommandLineRunner customRunner() {
        return (args) -> {
            System.out.println("动态码进行了更换");

            inviteCode = new Random(System.currentTimeMillis()).nextInt(90000)+10000;
            System.out.println(inviteCode);
        };
    }


    /**
     * it's for set http url auto change to https
     */
    @Bean
    public TomcatServletWebServerFactory servletContainer() { //springboot2 新变化
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(createHTTPConnector());
        return tomcat;
    }


    private Connector createHTTPConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        //同时启用http（8080）、https（443）两个端口
        connector.setScheme("http");
        connector.setSecure(false);
        connector.setPort(8080);
        connector.setRedirectPort(443);
        return connector;
    }

    @Configuration
    @Order(101)
    static class UserSecurityConfig extends WebSecurityConfigurerAdapter {
        @Resource
        CustomUserDeatailImpl userDetailsService;
        @Resource
        RedisUtils redisUtils;
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }

        @Bean
        public PasswordEncoder BCryptPasswordEncoder(){
            return new BCryptPasswordEncoder();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(BCryptPasswordEncoder());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 不指定path,本安全过滤链会匹配所有请求。
            http.csrf().disable()
                    .cors().and()
                    .authorizeRequests()
                    .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    .antMatchers("/qrcodeWebsocket/**").permitAll()
                    .antMatchers("/authentication/**").permitAll()
                    .antMatchers("/api/wx/login").permitAll()
                    .antMatchers("/record/**").hasAnyAuthority("ROLE_ADMIN")
                    .antMatchers("/api/**").hasAnyAuthority("ROLE_ADMIN","ROLE_WORKER","ROLE_USER")
                    .antMatchers("/api/admin/**").hasAnyAuthority("ROLE_ADMIN")
                    .antMatchers("/api/worker/**").hasAnyAuthority("ROLE_WORKER")
                    .antMatchers("/api/user/**").hasAnyAuthority("ROLE_USER")
                    .anyRequest().authenticated()

                    .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .addFilterAfter(new JavaWebTokenConfigurer.JavaWebTokenFilter(authenticationManagerBean(),redisUtils), SecurityContextHolderAwareRequestFilter.class)
                    .addFilterAfter(new JavaWebTokenConfigurer.UserPasswordFilter(authenticationManagerBean(),redisUtils),JavaWebTokenConfigurer.JavaWebTokenFilter.class)

            ;
        }
    }
}